/* Copyright (c) 2003-2007 Caleb Doise
 * 
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge,
 * publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

using System;
using System.Collections;
using System.Text;
using System.Runtime.InteropServices;

namespace SharpScraps.Win32
{

	[StructLayout(LayoutKind.Sequential)]
	public struct POINT 
	{
        public POINT(int x, int y)
        {
            this.x = x;
            this.y = y;
        }

        public POINT(System.Drawing.Point point)
        {
            this.x = point.X;
            this.y = point.Y;
        }

		public int x; 
		public int y;
	};

    [StructLayout(LayoutKind.Sequential)]
    public struct RECT 
    { 
        public int left; 
        public int top; 
        public int right; 
        public int bottom; 

		public int Width { get { return right - left; } }
		public int Height { get { return bottom - top; } }
    };


    public static class USER32
    {        

        [DllImport("User32.dll")]
        public static extern IntPtr GetDesktopWindow();

		[DllImport("User32.dll")]
		public static extern IntPtr GetShellWindow();

        [DllImport("User32.dll")]
        public static extern IntPtr GetWindowDC(IntPtr hWnd);

        [DllImport("User32.dll")]
        public static extern int ReleaseDC(IntPtr hWnd, IntPtr hdc);


        [DllImport("User32.dll")]
        public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);



        [DllImport("User32.dll")] 
        public static extern IntPtr FindWindow(string strclassName, string strWindowName);

        [DllImport("User32.dll")] 
        public static extern IntPtr FindWindowEx(
            IntPtr hwndParent,
            IntPtr hwndChildAfter,
            [MarshalAs(UnmanagedType.LPTStr)] string lpszClass,
            [MarshalAs(UnmanagedType.LPTStr)] string lpszWindow);
	
        [DllImport("User32.dll", CharSet=CharSet.Auto)]
        public static extern IntPtr SetFocus(IntPtr hWnd);


        [DllImport("User32.dll")]
        public static extern int GetWindowText(
            IntPtr hWnd,  
            StringBuilder buffer, 
            int nMaxCount);

        [DllImport("User32.dll")]
        public static extern int GetWindowTextLength(IntPtr hWnd);


        [DllImport("User32.dll", CharSet=CharSet.Auto)]
        public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);


        [DllImport("User32.dll")]
        public static extern bool IsWindowVisible(IntPtr hWnd);


        [DllImport("User32.dll")]
        public static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);
              

        [DllImport("User32.dll")]
        public extern static bool BringWindowToTop(IntPtr hWnd);

        [DllImport("User32.dll")]
        public extern static bool SetForegroundWindow(IntPtr hWnd);

        [DllImport("User32.dll")]
        public extern static IntPtr GetForegroundWindow();

        [DllImport("User32.dll")]
        public extern static bool ShowWindow(IntPtr hWnd, Int32 nCmdShow);


        [DllImport("User32.dll")]
        public extern static bool IsIconic(IntPtr hWnd);

        [DllImport("User32.dll")]
        public extern static bool IsZoomed(IntPtr hwnd);


		[DllImport("User32.dll")]
		public extern static IntPtr GetParent(IntPtr hwnd);


		[DllImport("User32.dll")]
		public extern static IntPtr WindowFromPoint(POINT point);



        [DllImport("User32.dll")]
        public extern static Int32 GetWindowLong(IntPtr hWnd, int nIndex);

        [DllImport("User32.dll")]
        public extern static Int32 SetWindowLong(IntPtr hWnd, int nIndex, Int32 dwNewLong);


        [DllImport("User32.dll")]
        public extern static Int32 SetWindowPos(
            IntPtr hWnd,
            IntPtr hWndInsertAfter,
            int X,
            int Y,
            int cx,
            int cy,
            UInt32 uFlags);


        [DllImport("User32.dll")]
        public extern static UInt32 GetWindowThreadProcessId(IntPtr hWnd, out Int32 lpdwProcessId); 
        
   

        [DllImport("User32.dll")]
        public extern static Int32 SetCapture(IntPtr hWnd);

        [DllImport("User32.dll")]
        public extern static bool ReleaseCapture();


        [DllImport("User32.dll")]
        public static extern bool InvalidateRect(IntPtr hWnd, IntPtr lpRect, bool bErase);

        [DllImport("User32.dll")]
        public static extern bool UpdateWindow(IntPtr hWnd);

        [DllImport("User32.dll")]
        public static extern bool RedrawWindow(IntPtr hWnd, IntPtr lprcUpdate, IntPtr hrgnUpdate, UInt32 flags);


        [DllImport("User32.dll")] 
        public static extern bool RegisterHotKey(IntPtr hwnd, int id, int fsModifiers, int vk);

        [DllImport("User32.dll")]
        public static extern bool UnregisterHotKey(IntPtr hWnd, int id);        
      

        [DllImport("User32.dll")]
        public static extern int SetScrollPos(IntPtr hWnd, int nBar, int nPos, bool bRedraw);

        [DllImport("User32.dll")]
        public static extern int GetScrollPos(IntPtr hWnd, int nBar);

        [DllImport("User32.dll")]
        public static extern bool GetScrollRange(IntPtr hWnd, int nBar, out int lpMinPos, out int lpMaxPos);        

        [DllImport("User32.dll")]
        public static extern bool SetScrollRange(IntPtr hWnd, int nBar, int nMinPos, int nMaxPos, bool bRedraw);

        

        #region Constants

        public static class ShowWindowConstants
        { 
            public const Int32 SW_HIDE             = 0;
            public const Int32 SW_SHOWNORMAL       = 1;
            public const Int32 SW_NORMAL           = 2;
            public const Int32 SW_SHOWMINIMIZED    = 2;
            public const Int32 SW_SHOWMAXIMIZED    = 3;
            public const Int32 SW_MAXIMIZE         = 3;
            public const Int32 SW_SHOWNOACTIVATE   = 4;
            public const Int32 SW_SHOW             = 5;
            public const Int32 SW_MINIMIZE         = 6;
            public const Int32 SW_SHOWMINNOACTIVE  = 7;
            public const Int32 SW_SHOWNA           = 8;
            public const Int32 SW_RESTORE          = 9;
            public const Int32 SW_SHOWDEFAULT      = 10;
            public const Int32 SW_FORCEMINIMIZE    = 11;
            public const Int32 SW_MAX              = 11;       
        } // class ShowWindowConstants


        public static class GetWindowLongConstants
        {
            public const Int32 GWL_WNDPROC         = -4;
            public const Int32 GWL_HINSTANCE       = -6;
            public const Int32 GWL_HWNDPARENT      = -8;
            public const Int32 GWL_STYLE           = -16;
            public const Int32 GWL_EXSTYLE         = -20;
            public const Int32 GWL_USERDATA        = -21;
            public const Int32 GWL_ID              = -12;
        } // class GetWindowLongConstants


        public static class SetWindowPosConstants
        {
            public static readonly IntPtr HWND_TOP        = new IntPtr(0);
            public static readonly IntPtr HWND_BOTTOM     = new IntPtr(1);
            public static readonly IntPtr HWND_TOPMOST    = new IntPtr(-1);
            public static readonly IntPtr HWND_NOTOPMOST  = new IntPtr(-2);

            public const UInt32 SWP_NOSIZE          = 0x0001;
            public const UInt32 SWP_NOMOVE          = 0x0002;
            public const UInt32 SWP_NOZORDER        = 0x0004;
            public const UInt32 SWP_NOREDRAW        = 0x0008;
            public const UInt32 SWP_NOACTIVATE      = 0x0010;
            public const UInt32 SWP_FRAMECHANGED    = 0x0020;  
            public const UInt32 SWP_SHOWWINDOW      = 0x0040;
            public const UInt32 SWP_HIDEWINDOW      = 0x0080;
            public const UInt32 SWP_NOCOPYBITS      = 0x0100;
            public const UInt32 SWP_NOOWNERZORDER   = 0x0200;  
            public const UInt32 SWP_NOSENDCHANGING  = 0x0400;  

            public const UInt32 SWP_DRAWFRAME       = SWP_FRAMECHANGED;
            public const UInt32 SWP_NOREPOSITION    = SWP_NOOWNERZORDER;
            
            public const UInt32 SWP_DEFERERASE      = 0x2000;
            public const UInt32 SWP_ASYNCWINDOWPOS  = 0x4000;           

        } // class SetWindowPosConstants


        public static class RedrawWindowConstants
        {
            public const UInt32 RDW_INVALIDATE              = 0x0001;
            public const UInt32 RDW_INTERNALPAINT           = 0x0002;
            public const UInt32 RDW_ERASE                   = 0x0004;
            public const UInt32 RDW_VALIDATE                = 0x0008;
            public const UInt32 RDW_NOINTERNALPAINT         = 0x0010;
            public const UInt32 RDW_NOERASE                 = 0x0020;
            public const UInt32 RDW_NOCHILDREN              = 0x0040;
            public const UInt32 RDW_ALLCHILDREN             = 0x0080;
            public const UInt32 RDW_UPDATENOW               = 0x0100;
            public const UInt32 RDW_ERASENOW                = 0x0200;
            public const UInt32 RDW_FRAME                   = 0x0400;
            public const UInt32 RDW_NOFRAME                 = 0x0800;
        } // class RedrawWindowConstants


        public static class WindowStyleConstants
        {
            public const long WS_EX_DLGMODALFRAME     = 0x00000001L;
            public const long WS_EX_NOPARENTNOTIFY    = 0x00000004L;
            public const long WS_EX_TOPMOST           = 0x00000008L;
            public const long WS_EX_ACCEPTFILES       = 0x00000010L;
            public const long WS_EX_TRANSPARENT       = 0x00000020L;

            public const long WS_EX_MDICHILD          = 0x00000040L;
            public const long WS_EX_TOOLWINDOW        = 0x00000080L;
            public const long WS_EX_WINDOWEDGE        = 0x00000100L;
            public const long WS_EX_CLIENTEDGE        = 0x00000200L;
            public const long WS_EX_CONTEXTHELP       = 0x00000400L;

            public const long WS_EX_RIGHT             = 0x00001000L;
            public const long WS_EX_LEFT              = 0x00000000L;
            public const long WS_EX_RTLREADING        = 0x00002000L;
            public const long WS_EX_LTRREADING        = 0x00000000L;
            public const long WS_EX_LEFTSCROLLBAR     = 0x00004000L;
            public const long WS_EX_RIGHTSCROLLBAR    = 0x00000000L;

            public const long WS_EX_CONTROLPARENT     = 0x00010000L;
            public const long WS_EX_STATICEDGE        = 0x00020000L;
            public const long WS_EX_APPWINDOW         = 0x00040000L;

            public const long WS_EX_OVERLAPPEDWINDOW  = (WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE);
            public const long WS_EX_PALETTEWINDOW     = (WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST);

            public const long WS_EX_LAYERED           = 0x00080000;

            public const long WS_EX_NOINHERITLAYOUT   = 0x00100000L;
            public const long WS_EX_LAYOUTRTL         = 0x00400000L;

            public const long WS_EX_COMPOSITED        = 0x02000000L;
            public const long WS_EX_NOACTIVATE        = 0x08000000L;

        } // class WindowStyleConstants


        public static class ScrollBarConstants
        {
            public const int SB_HORZ = 0;
            public const int SB_VERT = 1;
        } // class ScrollBarConstants


        public static class RegisterHotKeyConstants
        {
            public const int MOD_ALT        = 0x1;
            public const int MOD_CONTROL    = 0x2;
            public const int MOD_SHIFT      = 0x4;
            public const int MOD_WIN        = 0x8;            
        } // class RegisterHotKeyConstants


        #endregion


    } // class USER32



    public static class USER32Helper
    {       

        public static string GetWindowText(IntPtr hwnd)
        {
            StringBuilder sb = new StringBuilder(352);
            USER32.GetWindowText(hwnd, sb, sb.Capacity - 2);

            return sb.ToString();
        } // GetWindowText


        public static string GetClassName(IntPtr hwnd)
        {
            StringBuilder sb = new StringBuilder(352);
            USER32.GetClassName(hwnd, sb, sb.Capacity - 2);

            return sb.ToString();
        } // GetClassName


        public static IntPtr FindChildWindowByCaption(IntPtr wnd, string caption)
        {
            IntPtr child = USER32.FindWindowEx(wnd, IntPtr.Zero, null, null);
            while (child != IntPtr.Zero)
            {
                StringBuilder sb = new StringBuilder(352);
                USER32.GetWindowText(child, sb, sb.Capacity - 2);

                if (sb.ToString() == caption)
                    return child;

                child = USER32.FindWindowEx(wnd, child, null, null);
            }

            return IntPtr.Zero;
        } // FindChildWindowByCaption



        private delegate bool EnumWindowsCallback(IntPtr hWnd, IntPtr param);


        public static IntPtr[] EnumWindows()
        {
            ArrayList list = new ArrayList();            

            GCHandle gch = GCHandle.Alloc(list);
            try
            {
                EnumWindowsCallback cb = new EnumWindowsCallback(EnumWindowsCallback_AddToList);
                EnumWindows(cb, (IntPtr)gch);                
            }
            finally
            {
                gch.Free();
            }

            return (IntPtr[])list.ToArray(typeof(IntPtr));
        } // EnumWindows


        public static IntPtr[] EnumChildWindows(IntPtr hWndParent)
        {
            ArrayList list = new ArrayList();            

            GCHandle gch = GCHandle.Alloc(list);
            try
            {
                EnumWindowsCallback cb = new EnumWindowsCallback(EnumWindowsCallback_AddToList);
                EnumChildWindows(hWndParent, cb, (IntPtr)gch);                
            }
            finally
            {
                gch.Free();
            }

            return (IntPtr[])list.ToArray(typeof(IntPtr));
        } // EnumChildWindows


        private static bool EnumWindowsCallback_AddToList(IntPtr hWnd, IntPtr param) 
        {
            GCHandle gch = (GCHandle)param;
            IList list = (IList)gch.Target;
            list.Add(hWnd);
            return true;
        } // EnumWindowsCallback_AddToList


        [DllImport("User32.dll")]
        private static extern int EnumWindows(EnumWindowsCallback cb, IntPtr param); 

        [DllImport("User32.dll")]
        private static extern int EnumChildWindows(IntPtr hWndParent, EnumWindowsCallback cb, IntPtr param); 
        

    } // class USER32Helper


} // namespace SharpScraps.Win32